#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
	ls(nomFich), ts() {
    fichier.open("Test.cpp", ios::out); //on ouvrre le fichier en ecriture
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
	arbre=programme();
	if (arbre->getError()==false) {
		cout << "Syntaxe correcte." << endl;
	}
	else {
		cout << "Syntaxe incorrecte !" << endl << endl;    
                fichier.close(); //on ferme le fichier
		exit(0);
	}
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme() {
	// <programme> ::= debut <seq_inst> fin FIN_FICHIER

	sauterSymCour("debut");
        
        // traduction dans le fichier en C++
        fichier << "#include <iostream>" << endl;
        fichier << "#include <stdlib>" <<endl;
        fichier << endl << "using namespace std;" << endl;
        fichier << endl << "int main(void) {" <<endl;
        
        
        
	Noeud* si = seqInst();
	sauterSymCour("fin");
        
        // fin de fichier traduit et fermeture
        fichier << endl << "}";
        fichier.close(); 
        
	testerSymCour("<FINDEFICHIER>");
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst() {
	// <seqInst> ::= <inst> ; { <inst> ; }
	bool berror=false;
	Noeud* test=NULL;
	NoeudSeqInst* si = new NoeudSeqInst();
	do {
		test=inst();
		si->ajouteInstruction(test);

		if (test->getError()==true || test==NULL) {
			berror=true;
			sauterSymCour(";");
		}
		else {
			sauterSymCour(";");
		}
	} while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="lire" || ls.getSymCour()=="ecrire" || ls.getSymCour()=="si" || ls.getSymCour()=="tantque" || ls.getSymCour()=="repeter" || ls.getSymCour()=="pour" || ls.getSymCour()=="selon");
	// tant que le symbole courant est un debut possible d'instruction...
	if (berror==true) {
		si->setError(true);
	}
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst()
// <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter>| <instLire> | <instEcrire>| <instPour>
{
	if (ls.getSymCour()=="lire")
	{
		return instLire();
	}
	else if (ls.getSymCour()=="ecrire")
	{
		return instEcrire();
	}
	else if (ls.getSymCour()=="<VARIABLE>")
	{
		return affectation();
	}
	else if (ls.getSymCour()=="si")
	{
		return instSi();
	}
	else if (ls.getSymCour()=="tantque")
	{
		return instTq();
	}
	else if (ls.getSymCour()=="repeter")
	{
		return instRepeter();
	}
	else if (ls.getSymCour()=="pour")
	{
		return instPour();
	}
	else if (ls.getSymCour()=="selon")
	{
		return instSelon();
	}
	else
		return NULL;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation() {
// <affectation> ::= <variable> = <expression>
	bool berror;
	bool berror2;
	berror=testerSymCour("<VARIABLE>");

	if (berror==false) {
		Noeud* var = ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
		berror2=sauterSymCour("=");
		if (berror2==false) {
			Noeud* exp = expression();
			return new NoeudAffectation(var,exp);
		}
		else {
			return new NoeudError();
		}
	}
	else {
		return new NoeudError();
	}
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::terme() {
// <terme> ::= <facteur> {<opMult> <facteur>}

	Noeud* fact = facteur();

	while (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		Symbole operateur = opMult();
		Noeud* factDroit=facteur();
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit);
	}
	return fact;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression() {
//<expression> ::= <terme> { <opAdd> <terme> }

	Noeud* term = terme();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
		Symbole operateur = opAdd();
		Noeud* termeDroit=terme();
		term = new NoeudOperateurBinaire(operateur,term,termeDroit);
	}
	return term;
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  <opUnaire> <expOu> | (<expOu>)
	Noeud* fact=NULL;

	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>") {
		fact=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
		fact->setError(false);
		return fact;
	} else if (ls.getSymCour()=="-") {
		ls.suivant();
		// on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
		fact = new NoeudOperateurBinaire(Symbole("-"), ts.chercheAjoute(Symbole("0")), expOu());
		return fact;
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		fact=expression();
		sauterSymCour(")");
		return fact;
	} else
		erreur("<facteur>");
		return new NoeudError();
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expEt()
//<expEt> ::= <relation> { et <relation> }
{
	Noeud* fact = relation();
	while(ls.getSymCour()=="et")
	{
		Symbole operateur = ls.getSymCour();
                ls.suivant();
                
		Noeud* factDroit = relation();
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit);
	}
	return fact;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expOu()
//<expOu> ::= <expEt> { ou <expEt> }
{
	Noeud* fact = expEt();
	while(ls.getSymCour()=="ou")
	{
		Symbole operateur = ls.getSymCour();
                ls.suivant();
                
		Noeud* factDroit = expEt();
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit);
	}
	return fact;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::relation()
//<relation> ::= <expression> { <opRel> <expression> }
{
	Noeud* exp = expression();
	while(ls.getSymCour()=="==" 
                || ls.getSymCour()=="!=" 
                || ls.getSymCour()=="<" 
                || ls.getSymCour()==">" 
                || ls.getSymCour()=="<=" 
                || ls.getSymCour()==">=")
	{
		Symbole operateur = ls.getSymCour();
                ls.suivant();
                
		Noeud* expDroit = expression();
		exp = new NoeudOperateurBinaire(operateur,exp,expDroit);
	}
	return exp;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opAdd() {
// <opAdd> ::= + | -
    Symbole error;
    Symbole operateur;
    if (ls.getSymCour()=="+"
            || ls.getSymCour()=="-")
    {
                operateur=ls.getSymCour();
		ls.suivant();
		return operateur;
    }
    else {
		erreur("<opAdd>");
		return error;
    }
    
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opMult() {
// <opMult> ::= * | /
    Symbole error;
    Symbole operateur;
    if (ls.getSymCour()=="*"
            || ls.getSymCour()=="/")
    {
                operateur=ls.getSymCour();
		ls.suivant();
		return operateur;
    }
    else {
		erreur("<opMult>");
		return error;
    } 
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instLire()
// <instLire> ::= lire ( <variable> )
{
	Symbole operateur = ls.getSymCour();
        ls.suivant();
        
	Noeud* variable=NULL;
	Noeud* l=NULL;
	sauterSymCour("(");
	if (ls.getSymCour()=="<VARIABLE>")
	{
		variable=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
		sauterSymCour(")");
		l= new NoeudIO(operateur,variable);
		return l;
	}
	else {
		erreur("<instLire>");
		return new NoeudError();
	}
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instEcrire()
// <instEcrire> ::= ecrire (<expression> | <chaine> )
{
	Symbole operateur = ls.getSymCour();
        ls.suivant();
        
	Noeud* expr=NULL;
	Noeud* e=NULL;
	sauterSymCour("(");
	if (ls.getSymCour()=="<CHAINE>")
	{
		expr=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
		sauterSymCour(")");
		e= new NoeudIO(operateur,expr);
		return e;
	}
	else if (ls.getSymCour()=="<VARIABLE>") 
	{
		expr=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
		sauterSymCour(")");
		e= new NoeudIO(operateur,expr);
		return e;
	}
	else {
		erreur("<instEcrire>");
		return new NoeudError();
	}
}


////////////////////////////////////////////////////////////////////////////////	
Noeud* LecteurPhraseAvecArbre::instSi() {
//<instSi> ::= si ( <expOu>) <seqInst> {sinonsi ( <expOu> ) <seqInst> } [sinon <seqInst> ] finsi
	
	vector <Noeud*> tabCond;
	vector <Noeud*> tabInst;

	sauterSymCour("si");
	sauterSymCour("(");
	tabCond.push_back(expOu());
	sauterSymCour(")");
	tabInst.push_back(seqInst());


	while (ls.getSymCour() == "sinonsi")
	{
		sauterSymCour("sinonsi");
		sauterSymCour("(");
		tabCond.push_back(expOu());
		sauterSymCour(")");
		tabInst.push_back(seqInst());

	}
	if (ls.getSymCour() == "sinon")
	{
		sauterSymCour("sinon");
		tabInst.push_back(seqInst());
	}
	else {
		erreur("<instSi>");
		return new NoeudError();
	}
	sauterSymCour("finsi");
	return new NoeudInstSi(tabCond, tabInst);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instTq() {
//<instTq> ::= tantque ( <expOu> ) <seqInst> fintantque

	Symbole operateur = ls.getSymCour();
        ls.suivant();
        
	sauterSymCour("(");
	Noeud* cond = expOu();
	sauterSymCour(")");
	Noeud* si = seqInst();
	sauterSymCour("fintantque");

	return new NoeudBoucle(operateur,cond,si);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instRepeter() {
//<instRepeter> ::= repeter <seqInst> jusqua (<expOu>)
	Symbole operateur = ls.getSymCour();
        ls.suivant();
        
	Noeud* si = seqInst();
	sauterSymCour("jusqua");
	sauterSymCour("(");	
	Noeud* cond = expOu();
	sauterSymCour(")");


	return new NoeudBoucle(operateur,cond,si);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instPour() {
//<instPour> ::= pour (<affectation> ( <expOu> ) <affectation>) <seqInst> finpour 

	Symbole operateur = ls.getSymCour();
        ls.suivant();
        
	sauterSymCour("(");
	Noeud* aff1=affectation();
	sauterSymCour("(");
	Noeud* cond = expOu();
	sauterSymCour(")");
	Noeud* aff2=affectation();
	sauterSymCour(")");
	Noeud* Inst=seqInst();
	sauterSymCour("finpour");

	return new NoeudPour(operateur,cond,Inst,aff1,aff2);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instSelon() {
//<instSelon> ::= selon (<variable>): cas (<entier>) <seqInst> {cas(<entier>) <seqInst>} finselon
	vector <Noeud*> tabCond;
	vector <Noeud*> tabInst;
	Noeud * var=NULL;
	

	sauterSymCour("selon");
	sauterSymCour("(");
	if (ls.getSymCour()=="<VARIABLE>")
	{
			var=ts.chercheAjoute(ls.getSymCour());
			ls.suivant();

			sauterSymCour(")");
			sauterSymCour(":");
			sauterSymCour("cas");		
			sauterSymCour("(");

			Noeud * var2=NULL;
			var2=ts.chercheAjoute(ls.getSymCour());

			Noeud* cond = new NoeudOperateurBinaire(Symbole("=="),var,var2);
			tabCond.push_back(cond);

			ls.suivant();
			sauterSymCour(")");
			tabInst.push_back(seqInst());

			while (ls.getSymCour() == "cas")
			{
				sauterSymCour("cas");
				sauterSymCour("(");

				Noeud * var2=NULL;
				var2=ts.chercheAjoute(ls.getSymCour());

				Noeud* cond = new NoeudOperateurBinaire(Symbole("=="),var,var2);
				tabCond.push_back(cond);

				ls.suivant();
				sauterSymCour(")");
				tabInst.push_back(seqInst());
			}

			sauterSymCour("finselon");

			return new NoeudInstSi(tabCond,tabInst);
	}
	else {
		erreur("<VARIABLE>");
		return new NoeudError();
	}


}

////////////////////////////////////////////////////////////////////////////////
bool LecteurPhraseAvecArbre::testerSymCour(string ch) {
	bool error=false;
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		error=true;

		do {
		ls.suivant();
		} while (ls.getSymCour()!=";");
		//exit(0); // plus tard, on levera une exception

	}

	return error;
}

////////////////////////////////////////////////////////////////////////////////
bool LecteurPhraseAvecArbre::sauterSymCour(string ch) {
	bool test;
	test=testerSymCour(ch);
	if (test==false)
		ls.suivant();

	return test;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;


		do {
		ls.suivant();
		} while (ls.getSymCour()!=";");
	//exit(0); // plus tard, on levera une exception
}       
